using System;
using System.Collections.Generic;
using UnityEngine;

public class SoundItem {
  public int Index { get; set; }
  public float Time { get; set; }
  public float Volume { get; set; }
  public int Frequency { get; set; }
  public float Offset { get; set; }
  public string Path { get; set; }

  public SoundItem(XmlNode node) {
    Index = node.GetInt("Index");
    Time = node.GetFloat("Time");
    Volume = node.GetInt("Volume", 100) * 0.01f;
    Frequency = node.GetInt("Frequency", 100);
    Offset = node.GetFloat("Offset");
    Path = node.InnerText;
  }

  public override string ToString() {
    return $"SoundItem(Index={Index}, Time={Time}, Volume={Volume}, Frequency={Frequency}, Offset={Offset}, Path={Path})";
  }
}

public class SoundPack {
  public string Name { get; private set; }
  public Dictionary<int, SoundItem> Items { get; private set; }

  public SoundPack(string name) {
    Name = name;
    Items = new Dictionary<int, SoundItem>();
  }

  public void AddItem(SoundItem item) {
    Items[item.Index] = item;
  }

  public SoundItem GetItem(int index) {
    if (Items.TryGetValue(index, out SoundItem item)) {
      return item;
    }
    return null;
  }
}

public class SoundManager {
  private static SoundManager _instance;
  public static SoundManager Instance {
    get {
      if (_instance == null) {
        _instance = new SoundManager();
      }
      return _instance;
    }
  }

  private Dictionary<string, SoundPack> _soundPacks;

  private SoundManager() {
    _soundPacks = new Dictionary<string, SoundPack>(StringComparer.OrdinalIgnoreCase);
  }

  /// <summary>
  /// 添加声音包
  /// </summary>
  /// <param name="name">声音包名称</param>
  /// <param name="xml">包含声音数据的XmlReader</param>
  public void Add(string name, XmlReader xml) {
    if (_soundPacks.ContainsKey(name)) {
      throw new ArgumentException($"Sound pack '{name}' already exists");
    }

    SoundPack pack = new(name);
    XmlNode root = xml.Root;

    // 遍历所有子节点
    foreach (var childList in root.Children.Values) {
      foreach (var child in childList) {
        // 只处理名为"Item"的节点
        if (child.Name.Equals("Item", StringComparison.OrdinalIgnoreCase)) {
          SoundItem item = new(child);
          pack.AddItem(item);
        }
      }
    }

    _soundPacks.Add(name, pack);
  }

  /// <summary>
  /// 获取声音项
  /// </summary>
  /// <param name="packName">声音包名称</param>
  /// <param name="index">声音项索引</param>
  /// <returns>找到的声音项，如果未找到则返回null</returns>
  public SoundItem GetSound(string packName, int index) {
    if (_soundPacks.TryGetValue(packName, out SoundPack pack)) {
      return pack.GetItem(index);
    }
    return null;
  }

  /// <summary>
  /// 检查是否存在指定名称的声音包
  /// </summary>
  public bool HasPack(string packName) {
    return _soundPacks.ContainsKey(packName);
  }

  /// <summary>
  /// 移除声音包
  /// </summary>
  public void Remove(string packName) {
    _soundPacks.Remove(packName);
  }

  /// <summary>
  /// 清空所有声音包
  /// </summary>
  public void Clear() {
    _soundPacks.Clear();
  }

  // 创建变速音频剪辑的方法
  public static AudioClip CreateSpeedAdjustedClip(AudioClip original, float speed) {
    // 计算新的采样数
    int newSamples = Mathf.RoundToInt(original.samples / speed);

    // 创建新剪辑
    AudioClip newClip = AudioClip.Create(
        $"{original.name}_speed{speed}x",
        newSamples,
        original.channels,
        original.frequency,
        false
    );

    // 获取原始数据
    float[] originalData = new float[original.samples * original.channels];
    original.GetData(originalData, 0);

    // 创建变速数据
    float[] newData = new float[newSamples * original.channels];

    // 简单重采样（实际项目可能需要更复杂的插值算法）
    for (int i = 0; i < newData.Length; i++) {
      float pos = i * speed;
      int posInt = Mathf.FloorToInt(pos);
      float frac = pos - posInt;

      if (posInt + 1 < originalData.Length) {
        newData[i] = originalData[posInt] * (1 - frac) + originalData[posInt + 1] * frac;
      } else {
        newData[i] = originalData[Mathf.Min(posInt, originalData.Length - 1)];
      }
    }

    newClip.SetData(newData, 0);
    return newClip;
  }

}